package com.dotflat.physicalevaluate.service.impl;

import com.aspose.words.Document;
import com.dotflat.physicalevaluate.domain.importexport.PhysicEvaluateExportRecord;
import com.dotflat.physicalevaluate.domain.pe.PERecord;
import com.dotflat.physicalevaluate.domain.pe.RelRecordMeasure;
import com.dotflat.physicalevaluate.repository.ExportRecordRepository;
import com.dotflat.physicalevaluate.service.EvaluateConclusionService;
import com.dotflat.physicalevaluate.service.PhysicEvaluateExportService;
import com.dotflat.physicalevaluate.service.PhysicEvaluateService;
import com.dotflat.physicalevaluate.service.PhysicRemoteChartService;
import com.matt.Application;
import com.matt.commons.dto.sso.StaffDTO;
import com.matt.commons.exception.BusinessException;
import com.matt.foundation.dto.AreaDetailDTO;
import com.matt.foundation.model.ErrorCode;
import com.matt.foundation.model.UnionTypeID;
import com.matt.service.UploadService;
import com.tuo51.evaluate.service.EvaluateV2ExportService.ExportType;
import com.tuo51.foudation.utils.CopyUtils;
import com.tuo51.foudation.utils.DateUtil;
import com.tuo51.foudation.utils.EvaluationReportUtils;
import com.tuo51.foudation.utils.export.HealthReportUtil;
import freemarker.cache.ClassTemplateLoader;
import freemarker.cache.TemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateExceptionHandler;
import freemarker.template.TemplateNotFoundException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.*;
import java.util.List;
import java.util.Map;

import static freemarker.template.Configuration.VERSION_2_3_26;

@Service
public class PhysicEvaluateExportServiceImpl implements PhysicEvaluateExportService {

    @Autowired
    ExportRecordRepository exportRecordRepository;

    @Autowired
    UploadService uploadService;

    @Autowired
    PhysicRemoteChartService physicRemoteChartService;

    @Autowired
    private PhysicEvaluateService physicEvaluateService;

    @Autowired
    private EvaluateConclusionService conclusionService;

    private static Configuration configuration = null;

    //临时文件写出路径
    private static String tempPath = null;

    //初始化
    static {
        if(File.separatorChar == '/'){
            tempPath =  "/tmp/evaluate_report";
        }else {
            tempPath =  "d:";
        }
    }

    //
    static {
        try {
            configuration = new Configuration(VERSION_2_3_26);
            configuration.setDefaultEncoding("utf-8");
            configuration.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);

            TemplateLoader tl = new ClassTemplateLoader(Application.class,"/templates");
            configuration.setTemplateLoader(tl);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private String safeXML(String str){
        return str.replaceAll("\\<", "&lt;").replaceAll("\\>", "&gt;");
    }


    @Override
    public String exportEvaluateReport(String channel, PERecord record, StaffDTO staff, AreaDetailDTO area, ExportType exportType){
        //create folder
        File tf = new File(tempPath);
        if(!tf.exists()){
            Boolean success = tf.mkdirs();
            if(success){
                System.out.println("create file success::" + tempPath);
            }
        }

        String tempFilePath = tempPath + File.separatorChar + record.getId() +"_evaluateV2.xml";
        Writer out = null;
        try {
            //生成文档
            Template temple = null;
            String templateName = exportType.getTemplateName();
            if(StringUtils.isNotEmpty(channel)){
                templateName = templateName  + "_" + channel;
            }

            try {
                temple = configuration.getTemplate(templateName);//获取模板
            }catch (TemplateNotFoundException e){
                temple = configuration.getTemplate(exportType.getTemplateName());
            }

            out = new OutputStreamWriter(new FileOutputStream(tempFilePath));//生成最终页面并写到文件

            Map data = evaluateExportObject(null, record, null, area, exportType);

            temple.process(data, out);//处理

            return tempFilePath;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException e) {

            }

        }

        return  null;
    }


    @Override
    public String exportEvaluateReportToOSS(String channel, String evaluateRecordId, StaffDTO staff, AreaDetailDTO area, ExportType exportType, boolean force){
        PhysicEvaluateExportRecord exportRecord = exportRecordRepository.findByTypeID(UnionTypeID.of(evaluateRecordId, exportType.getType()));
        if(exportRecord != null){
            return exportRecord.getStaticURL();
        }

//        PERecord record = recordRepository.getOneByCreateTeacherIdAndIdAndDeletedIsFalse(staff.getId(), evaluateRecordId);
        PERecord record = physicEvaluateService.getEvaluateDetailById(staff.getAreaId(), evaluateRecordId, null);
        if(record == null){
            throw  new BusinessException(ErrorCode.EVALUATE_RECORD_NOT_EXIST, "报告不存在");
        }

        if( force == false && !record.getPaid() ){
            throw  new BusinessException(ErrorCode.REPORT_PAID_NEEDED, "报告没有付费，无法导出");
        }

        String tempFilePath = exportEvaluateReport(channel, record, staff, area, exportType);

        if (exportType == ExportType.WORD){
            //处理成真的doc
            String tt = convertXmlToDoc(tempFilePath);
            if (StringUtils.isNotEmpty(tt)){
                tempFilePath = tt;
            }
//        }else if (exportType == ExportType.PDF){
//            //处理成真的pdf
//            String tt = convertXmlToPDF(tempFilePath);
//            if (StringUtils.isNotEmpty(tt)){
//                tempFilePath = tt;
//            }
        }

        String ossFile = uploadService.uploadLocalFile(tempFilePath, exportType, record.getChildrenName()+"宝宝的报告");

        //保存
        if(StringUtils.isNotEmpty(ossFile)) {
            exportRecord = PhysicEvaluateExportRecord.of(exportType.getType(), record.getId(), ossFile);
            exportRecordRepository.save(exportRecord);
            return ossFile;
        }else{
            throw  new BusinessException(ErrorCode.ERROR, "导出失败");
        }
    }

    private String convertXmlToPDF(String docFile) {

        try {
            // Open a document.
            Document doc = new Document(docFile);
            // Save document.
            String outputFileName = docFile + ".pdf";

            doc.save(outputFileName);

            return outputFileName;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    private String convertXmlToDoc(String docFile) {

        try {
            // Open a document.
            Document doc = new Document(docFile);
            // Save document.
            String outputFileName = docFile + ".doc";

            doc.save(outputFileName);

            return outputFileName;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    @Override
    public Map evaluateExportObject(String reportId, PERecord record, StaffDTO staff, AreaDetailDTO area, ExportType exportType ){

        if (record == null){
            record = physicEvaluateService.getEvaluateDetail(staff.getAreaId(), reportId);
        }

        Map data = CopyUtils.transBean2Map(record);

        //处理渲染数据
        {
            data.put("areaName", area.getName());
            data.put("areaAddress", area.getAddress());
            data.put("areaPhone", area.getContactNumber());
        }

        double height = 0;
        double weight = 0;
        double header = 0;
        float actualMonth = (float) DateUtil.betweenMonthsV2(record.getEvaluatingDate(), record.getBirthday());

        if(StringUtils.isNotBlank(record.getHeight()) &&  StringUtils.isNotBlank(record.getWeight()) ) {
            height = Double.parseDouble(record.getHeight())/10;
            weight = Double.parseDouble(record.getWeight())/10;
            header = StringUtils.isNotBlank(record.getHeader()) ? Double.parseDouble(record.getHeader())/10 : 0;
        }else {
            if(height <= 0.01 || weight <= 0.01){
                throw new BusinessException(ErrorCode.VERSION_ERROR, "不正确的儿保测评身高体重");
            }
        }

        String gender = record.getGender() == 0 ? "女" : "男";

        int fullScore = 0;   //计算总分
        //仅word需要静态报表图片
        if (exportType == ExportType.WORD /*|| exportType == ExportType.PDF*/) {
            //生成身高报表图表
            String heightImg = HealthReportUtil.encodedHeightChart(gender, actualMonth, (float) height);

            //生成体重图表
            String weightImg = HealthReportUtil.encodedWeightChart(gender, actualMonth, (float) weight);

            //img
            data.put("heightImg", heightImg);
            data.put("weightImg", weightImg);

            //测评柱状图

            List<RelRecordMeasure> rels = record.getRels();

            if (rels.size() == 0){
                throw new BusinessException(ErrorCode.EVALUATE_RECORD_NOT_EXIST, "测评记录有错误");
            }

            //创建图表
            Double [] barValues = new Double[6];
            String [] names = new String[6];

            for(int i = 0 ; i < rels.size(); i++){
                RelRecordMeasure c = rels.get(i);

                int index = c.getSeq() - 3;
                if (index < 0){
                    //不计算身高体重
                    rels.remove(i--);
                    continue;
                }
                barValues[index] = c.getRankVal() * 1.0 ;
                names[index] = c.getDimension();

                fullScore += barValues[index];
            }

            data.put("fullScore", fullScore);
            data.put("fullScoreDesc", conclusionService.rankDesc(fullScore));

            data.put("dqValues", barValues);
            data.put("dNames", names);

            String evaluateImg = physicRemoteChartService.getRemoteEvaluateChartBase64(names, barValues);
            data.put("evaluateImg", evaluateImg);

        }

        //下次测评时间
        data.put("nextEvaluatingDate", EvaluationReportUtils.nextEvaluateDate(record.getEvaluatingDate(), record.getMonth()));

        //生成结论文本
        String heightConclusion = HealthReportUtil.heightConclusion(record.getChildrenName(), gender, height, record.getMonth());
        String weightConclusion = HealthReportUtil.weightConclusion(record.getChildrenName(), gender, height, weight, record.getMonth());

        //heightConclusion
        //weightConclusion
        data.put("heightConclusion", safeXML(heightConclusion));
        data.put("weightConclusion", safeXML(weightConclusion));

        //base info
        data.put("weight", weight);
        data.put("height", height);
        data.put("header", header);

        //结论
        String complexConclusion = conclusionService.getComplexConclusion(record.getChildrenName(), fullScore);
        String normalConclusion = conclusionService.getNormalConclusion(record);

        data.put("complexConclusion", complexConclusion);
        data.put("normalConclusion", normalConclusion);

//        //仅h5需要这个
//        if (exportType == ExportType.H5) {
//            data.put("jsonDetail", JSON.toJSONString(data));
//        }

        return data;
    }
}
